package pos.utils;

import java.util.*;
import javax.media.j3d.*;
import javax.vecmath.Point3d;

/**
 * 逐帧调用器，采用观察者模式设计，所有被添加到此调用器的对象将在每次画面被渲染之后得到一次调用
 * 此调用器适合所有需要画面同步的对象
 * @author plus
 */
public class PreFrameInvoker extends Behavior {

    private WakeupOnElapsedFrames FrameCondition;
    private long count = 0;
    private static ArrayList<Invokeable> Liseners=new ArrayList<Invokeable>();
    private static Invokeable SingleLisener;
    private boolean bSingleInvoking=false;
    /**
     * 初始化一个逐帧调用器
     */
    public PreFrameInvoker() {
        FrameCondition = new WakeupOnElapsedFrames(1);
        this.setSchedulingBounds(new BoundingSphere(new Point3d(0d, 0d, 0d), 15000));
        count = System.nanoTime();
    }
    
    
    /**
     * 初始化行为，仅允许java3d行为控制器调用
     */
    public void initialize() {
        this.wakeupOn(FrameCondition);
    }
    /**
     * 添加一个需要被逐帧调用的对象
     * @param Lisener 需要被逐帧调用的对象
     */
    public void addLisener(Invokeable Lisener){
        Liseners.add(Lisener);
        this.bSingleInvoking=false;
    }
    /**
     * 添加一个需要被独占逐帧调用的对象
     * @param Lisener 需要被独占逐帧调用的对象
     */
    public void addSingleLisener(Invokeable Lisener){
        SingleLisener=Lisener;
        this.bSingleInvoking=true;
    }
    /**
     * 移除一个需要被逐帧调用的对象
     * @param Lisener 需要被移除的对象
     */
    public void removeLisener(Invokeable Lisener){
        Liseners.remove(Lisener);
    }
    /**
     * 移除一个需要被独占逐帧调用的对象
     * @param Lisener 需要被移除的独占对象
     */
    public void removeSingleLisener(Invokeable Lisener){
        this.bSingleInvoking=false;
        SingleLisener=null;
    }
    /**
     * 发生行为，仅允许java3d行为控制器调用
     * @param criteria 出发行为的条件序列
     */
    public void processStimulus(Enumeration criteria) {
        double TickCount=0;
        while (criteria.hasMoreElements()) {
            WakeupCriterion currentCriterion = (WakeupCriterion) criteria.nextElement();
            if (currentCriterion.equals(FrameCondition)) {
                TickCount = (System.nanoTime() - count) / 1000000000d;
                count=System.nanoTime();
                if (!bSingleInvoking)
                    for (int LisenerID=0; LisenerID<Liseners.size(); LisenerID++)
                        Liseners.get(LisenerID).invoke(TickCount);
                else
                    SingleLisener.invoke(TickCount);
            } 
        }
        this.wakeupOn(FrameCondition);
    }
}

